/**
 * Copyright (C) 2013 DaiKit.com - daikit4gxt module (admin@daikit.com)
 *
 *         Project home : http://code.daikit.com/daikit4gxt
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.daikit.daikit4gxt.client.ui.editor.advanced;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import com.daikit.daikit4gxt.client.DkBaseMain;
import com.daikit.daikit4gxt.client.propertyaccess.DkValueWrapperPropertyAccess;
import com.daikit.daikit4gxt.client.ui.UIInvalidatable;
import com.daikit.daikit4gxt.client.ui.cell.CellColumnResizer;
import com.daikit.daikit4gxt.client.ui.cell.IconButtonCell;
import com.daikit.daikit4gxt.client.ui.cell.ListStoreIconButtonCell;
import com.daikit.daikit4gxt.shared.bean.DkDataWrapper;
import com.google.gwt.cell.client.Cell;
import com.sencha.gxt.cell.core.client.form.FieldCell;
import com.sencha.gxt.data.shared.ListStore;
import com.sencha.gxt.widget.core.client.button.TextButton;
import com.sencha.gxt.widget.core.client.container.VerticalLayoutContainer;
import com.sencha.gxt.widget.core.client.container.VerticalLayoutContainer.VerticalLayoutData;
import com.sencha.gxt.widget.core.client.event.SelectEvent;
import com.sencha.gxt.widget.core.client.grid.ColumnConfig;
import com.sencha.gxt.widget.core.client.grid.ColumnModel;
import com.sencha.gxt.widget.core.client.grid.Grid;
import com.sencha.gxt.widget.core.client.tips.QuickTip;
import com.sencha.gxt.widget.core.client.toolbar.FillToolItem;
import com.sencha.gxt.widget.core.client.toolbar.ToolBar;


/**
 * An editor for a multiple value list
 *
 * @author tcaselli
 * @version $Revision$ Last modifier: $Author$ Last commit: $Date$
 * @param <M>
 */
public abstract class DkMultipleValueEditorGrid<M extends Serializable> extends AbstractDkHideableAdapterField<List<M>> implements UIInvalidatable
{

	protected final ListStore<DkDataWrapper<M>> store;
	protected final IconButtonCell deleteCell;
	protected final TextButton buttonNew;
	protected final Grid<DkDataWrapper<M>> grid;
	protected final DkValueWrapperPropertyAccess<M> props;
	private boolean enabled = true;

	protected final VerticalLayoutContainer verticalLayoutContainer;

	/**
	 * Constructor
	 *
	 * @param props
	 *           the {@link DkValueWrapperPropertyAccess}
	 */
	public DkMultipleValueEditorGrid(final DkValueWrapperPropertyAccess<M> props)
	{
		super(new VerticalLayoutContainer());
		this.props = props;
		setHeight(DkBaseMain.config().getEditorGridHeight());
		this.store = new ListStore<DkDataWrapper<M>>(props.key());
		store.setAutoCommit(true);
		final List<ColumnConfig<DkDataWrapper<M>, ?>> columns = getColumnConfigs();

		final ColumnConfig<DkDataWrapper<M>, String> columnDelete = new ColumnConfig<DkDataWrapper<M>, String>(props.delete(), 30, "");
		columnDelete.setMenuDisabled(true);
		columnDelete.setResizable(false);
		columnDelete.setSortable(false);
		columnDelete.setFixed(true);
		deleteCell = new ListStoreIconButtonCell<DkDataWrapper<M>>(DkBaseMain.icons().delete2_16(), getDeleteTooltip(), store)
		{
			@Override
			protected void onClick(final DkDataWrapper<M> model, final int column, final int row, final String modelKey)
			{
				onDeleteButtonClicked(model);
			}

			@Override
			protected boolean isCellIconVisible(final DkDataWrapper<M> model, final int column, final int row, final String modelKey)
			{
				return isModelDeletable(model, column, row, modelKey);
			}
		};
		columnDelete.setCell(deleteCell);
		columns.add(columnDelete);

		final ColumnModel<DkDataWrapper<M>> cm = new ColumnModel<DkDataWrapper<M>>(columns);

		grid = new Grid<DkDataWrapper<M>>(store, cm);
		new QuickTip(grid);
		verticalLayoutContainer = (VerticalLayoutContainer) getWidget();
		verticalLayoutContainer.setBorders(true);

		for (final ColumnConfig<DkDataWrapper<M>, ?> columnConfig : columns)
		{
			if (columnConfig.getCell() instanceof FieldCell)
			{
				grid.getColumnModel().addColumnWidthChangeHandler(new CellColumnResizer<DkDataWrapper<M>>(columnConfig, (FieldCell<?>) columnConfig.getCell()));
			}
		}

		final ToolBar toolbar = new ToolBar();
		toolbar.add(new FillToolItem());
		buttonNew = new TextButton(DkBaseMain.i18n().label_new(), new SelectEvent.SelectHandler()
		{
			@Override
			public void onSelect(final SelectEvent event)
			{
				onNewButtonClicked();
			}
		});
		buttonNew.setIcon(DkBaseMain.icons().file_plus_16());

		toolbar.add(buttonNew);
		toolbar.setHeight(29);
		verticalLayoutContainer.add(toolbar, new VerticalLayoutData(1, 29));
		verticalLayoutContainer.add(grid, new VerticalLayoutData(1, 1));
	}

	protected List<ColumnConfig<DkDataWrapper<M>, ?>> getColumnConfigs()
	{
		final List<ColumnConfig<DkDataWrapper<M>, ?>> columns = new ArrayList<ColumnConfig<DkDataWrapper<M>, ?>>();
		final ColumnConfig<DkDataWrapper<M>, M> columnValue = new ColumnConfig<DkDataWrapper<M>, M>(props.value(), 250, DkBaseMain.i18n().label_value());
		columnValue.setCell(createCell());
		columns.add(columnValue);
		return columns;
	}

	/**
	 * Enable or disable buttons
	 *
	 * @param enabled
	 */
	@Override
	public void setEnabled(final boolean enabled)
	{
		buttonNew.setEnabled(enabled);
		grid.setEnabled(enabled);
		this.enabled = enabled;
	}

	@Override
	public final boolean isEnabled()
	{
		return enabled;
	}

	/**
	 * @return the delete tooltip
	 */
	protected String getDeleteTooltip()
	{
		return DkBaseMain.i18n().label_delete_this_entry();
	}

	/**
	 * Nothing done by default
	 */
	@Override
	public void invalidateUi()
	{
		// Nothing done by default
	}

	/**
	 * Set the new button tooltip
	 *
	 * @param tooltip
	 *           the tooltip
	 */
	public void setButtonNewTooltip(final String tooltip)
	{
		if (buttonNew != null)
		{
			buttonNew.setTitle(tooltip);
		}
	}

	/**
	 * Set the new button label
	 *
	 * @param label
	 *           the label
	 */
	public void setButtonNewLabel(final String label)
	{
		if (buttonNew != null)
		{
			buttonNew.setText(label);
		}
	}

	/**
	 * Delete button clicked
	 */
	protected void onDeleteButtonClicked(final DkDataWrapper<M> model)
	{
		store.remove(model);
	}

	/**
	 * Add button clicked
	 */
	protected void onNewButtonClicked()
	{
		final DkDataWrapper<M> newEntry = new DkDataWrapper<M>(createEntry());
		store.add(newEntry);
		grid.getSelectionModel().select(newEntry, false);
	}

	/**
	 * @return the store
	 */
	public ListStore<DkDataWrapper<M>> getStore()
	{
		return store;
	}

	protected abstract Cell<M> createCell();

	protected boolean isModelDeletable(final DkDataWrapper<M> model, final int column, final int row, final String modelKey)
	{
		return true;
	}

	/**
	 * May be overridden to provide default value for creation
	 *
	 * @return
	 */
	protected M createEntry()
	{
		return null;
	}

	/**
	 * @return the grid
	 */
	public Grid<DkDataWrapper<M>> getGrid()
	{
		return grid;
	}

	@Override
	public List<M> getValue()
	{
		store.commitChanges();
		return DkDataWrapper.convertBack(store.getAll());
	}

	@Override
	public void setValue(final List<M> value)
	{
		store.clear();
		if (value != null && value.size() > 0)
		{
			store.addAll(DkDataWrapper.convert(value));
		}
	}

	/**
	 * @return the button new
	 */
	public TextButton getButtonNew()
	{
		return buttonNew;
	}
}
